/*
 * 本example主要用来展示如何使用UTSCKernel库实现两种时间类型（UTC时间和地质时间）的编码与解码
 * 主要使用到IUTSCKernel.hpp
 * */

#include"IUTSCKernel.hpp"
#include<iostream>
using namespace NNU::UTSC::Kernel;
using namespace NNU::UTSC::Base;

// UTC基准时间使用UTSC库进行编码解码、层次查询、拓扑查询的操作示例
void utcTest();

// 地质基准时间使用UTSC库进行编码解码、层次查询、拓扑查询的操作示例
void geoTest();

// 时间范围测试
void rangeTest();

// 初始化UTC基准时间
UTSCTime* InitUTC();
void InitUTCRange(UTSCTime*& start, UTSCTime*& end);

// 初始化地质基准时间
UTSCTime* InitGeo();

// 时间编码
void encode(UTSCTime* time, UTSCElementCode*& code);
void encodeRange(UTSCTime* start, UTSCTime* end, UTSCElementCode*& code);

// 时间解码
void decode(UTSCElementCode* code, UTSCTime*& time);
void decodeRange(UTSCElementCode* code, UTSCTime*& start, UTSCTime*& end);

//时间层级结构关系查询
void utscStructQuery(UTSCStructType type, UTSCElementCode* code, UTSCElementCode*& result,int &size);

//时间拓扑关系查询
UTSCTopoType topoQuery(UTSCElementCode* code1, UTSCElementCode* code2,int type);

//打印编码结果
void MyprintDecode(UTSCTime*& decodetime);

//打印二进制形式结果
void printBinary(uint8_t n);

//打印16位中后N位
void printLastNBits(uint16_t num, int n);

//打印解码结果
void MyprintEncode(UTSCElementCode*& encodetime);

//打印拓扑查询结果
void printTopoQueryResult(int type);

int main()
{
    // UTC基准时间使用UTSC库进行编码解码、层次查询、拓扑查询的操作示例
    std::cout << "UTC基准时间示例：" << std::endl;
    utcTest();
    std::cout << std::endl << "/*********************************分隔符********************************/" << std::endl<< std::endl;
    // 地质基准时间使用UTSC库进行编码解码、层次查询、拓扑查询的操作示例
    std::cout << "地质基准时间示例：" << std::endl;
    geoTest();
    std::cout << std::endl << "/*********************************分隔符********************************/" << std::endl << std::endl;
    // 时间范围测试用例
    std::cout << "UTC时间范围示例：" << std::endl;
    rangeTest();
    system("pause");
    return 0;
}



/// <summary>
/// UTC基准时间使用UTSC库进行编码解码、层次查询、拓扑查询的操作示例
/// </summary>
void utcTest() {
    UTSCTime* orgTime = InitUTC();
    std::cout << "输入的时间为:" << std::endl;
    MyprintDecode(orgTime);
    std::cout << std::endl;
    // 存储编码信息结果
    UTSCElementCode* encodeResult = new UTSCElementCode();
    // 存储结构查询结果
    UTSCElementCode* parentRelationResult = new UTSCElementCode[2];
    UTSCElementCode* childrenRelationResult = new UTSCElementCode[2];
    UTSCElementCode* neighborRelationResult = new UTSCElementCode[2];
    // 存储解码信息结果
    UTSCTime* decodeResult = new UTSCTime();
    // 编码
    encode(orgTime, encodeResult);
    // 解码
    decode(encodeResult, decodeResult);
    // 打印编码結果
    std::cout << "编码结果为:" << std::endl;
    MyprintEncode(encodeResult);
    std::cout << std::endl;
    // 打印解码结果
    std::cout << "编码的解码结果为:" << std::endl;
    MyprintDecode(decodeResult);
    std::cout << std::endl;
    std::cout << std::endl;
    // 层级结构关系查询
    int size = 0;
    std::cout << "父时间查询如下:" << std::endl;
    utscStructQuery(Parent, encodeResult, parentRelationResult, size);
    std::cout << "子时间查询如下:" << std::endl;
    utscStructQuery(Children, encodeResult, childrenRelationResult, size);
    std::cout << "相邻时间查询如下:" << std::endl;
    utscStructQuery(Neighbor, encodeResult, neighborRelationResult, size);
    // 查询两个时间之间的拓扑关系（原始的编码和其相邻层次查询的结果进行拓扑关系查询）
    UTSCTopoType result = topoQuery(encodeResult, neighborRelationResult, 2);
    std::cout << "上述原始时间和其相邻时间的拓扑关系计算为:" << std::endl;
    printTopoQueryResult((int)result);
}

/// <summary>
/// 地质基准时间使用UTSC库进行编码解码、层次查询、拓扑查询的操作示例
/// </summary>
void geoTest()
{
    UTSCTime* orgTimeGeo = InitGeo();
    std::cout << "输入的时间为:" << std::endl;
    MyprintDecode(orgTimeGeo);
    std::cout << std::endl;
    // 存储编码信息结果
    UTSCElementCode* encodeResultGeo = new UTSCElementCode;
    // 存储结构查询结果
    UTSCElementCode* parentRelationResultGeo = new UTSCElementCode[2];
    UTSCElementCode* childrenRelationResultGeo = new UTSCElementCode[2];
    UTSCElementCode* neighborRelationResultGeo = new UTSCElementCode[2];
    // 存储解码信息结果
    UTSCTime* decodeResultGeo = new UTSCTime();
    // 编码
    encode(orgTimeGeo, encodeResultGeo);
    // 解码
    decode(encodeResultGeo, decodeResultGeo);
    // 打印编码結果
    std::cout << "编码结果为:" << std::endl;
    MyprintEncode(encodeResultGeo);
    std::cout << std::endl;
    // 打印解码结果
    std::cout << "编码的解码结果为:" << std::endl;
    MyprintDecode(decodeResultGeo);
    std::cout << std::endl;
    std::cout << std::endl;
    // 层级结构关系查询
    int size = 0;
    std::cout << "父时间查询如下:" << std::endl;
    utscStructQuery(Parent, encodeResultGeo, parentRelationResultGeo, size);
    std::cout << "子时间查询如下:" << std::endl;
    utscStructQuery(Children, encodeResultGeo, childrenRelationResultGeo, size);
    std::cout << "相邻时间查询如下:" << std::endl;
    utscStructQuery(Neighbor, encodeResultGeo, neighborRelationResultGeo, size);
    // 查询两个时间之间的拓扑关系（相邻层次查询的结果之间进行拓扑查询）
    auto resultGeo = topoQuery(&neighborRelationResultGeo[0], &neighborRelationResultGeo[1], 1);
    std::cout << "上述相邻时间的拓扑关系计算为:" << std::endl;
    printTopoQueryResult((int)resultGeo);
}

/// <summary>
/// 对于在一个节点上的时间范围和不在一个节点上的时间范围的测试用例
/// </summary>
void rangeTest()
{
    using namespace NNU::UTSC::Kernel;
    using namespace NNU::UTSC::Base;

    IUTSCKernel* p = CreateKernelObj();

    // 场景 A：同层且能被一个节点覆盖（2025-01-08 ~ 2025-01-15）
    UTSCTime* a1 = new UTSCTime(3);
    a1->system = UTSCTimeSystemType::UTC;
    a1->segmentTime[0] = { UTSCElementType::Year,  2025 };
    a1->segmentTime[1] = { UTSCElementType::Month, 1    };
    a1->segmentTime[2] = { UTSCElementType::Day,   8    };

    UTSCTime* a2 = new UTSCTime(3);
    a2->system = UTSCTimeSystemType::UTC;
    a2->segmentTime[0] = { UTSCElementType::Year,  2025 };
    a2->segmentTime[1] = { UTSCElementType::Month, 1    };
    a2->segmentTime[2] = { UTSCElementType::Day,   15   };

    // 编码
    std::vector<UTSCElementCode> A;
    p->encode(a1, a2, A);
    std::cout << "[A] 2025-01-08 ~ 2025-01-15 编码：" << std::endl;
    // 编码结果是一个编码数组，对于数组中的每一个编码逐个输出
    for (auto &c: A) {
        UTSCElementCode* enc = &c;
        MyprintEncode(enc);
        std::cout << std::endl;
    }
    // 解码
    UTSCTime* Astart=nullptr; UTSCTime* Aend=nullptr;
    p->decode(A, Astart, Aend);
    std::cout << "解码范围："; MyprintDecode(Astart); std::cout << " ~ "; MyprintDecode(Aend); std::cout << std::endl;

    // 场景 B：同层但不能单节点覆盖（2025-02 ~ 2025-06 → 2025年2~3月、4~5月、6月）
    UTSCTime* b1 = new UTSCTime(2);
    b1->system = UTSCTimeSystemType::UTC;
    b1->segmentTime[0] = { UTSCElementType::Year,  2025 };
    b1->segmentTime[1] = { UTSCElementType::Month, 2 };
    

    UTSCTime* b2 = new UTSCTime(3);
    b2->system = UTSCTimeSystemType::UTC;
    b2->segmentTime[0] = { UTSCElementType::Year,  2025 };
    b2->segmentTime[1] = { UTSCElementType::Month, 6 };

    // 编码
    std::vector<UTSCElementCode> B;
    p->encode(b1, b2, B);
    std::cout << "[B] 2025-02 ~ 2025-06 编码：" << std::endl;
    // 编码结果是一个编码数组，对于数组中的每一个编码逐个输出
    for (auto &c: B) {
        UTSCElementCode* enc = &c;
        MyprintEncode(enc);
        std::cout << std::endl;
    }
    // 解码
    UTSCTime* Bstart=nullptr; UTSCTime* Bend=nullptr;
    p->decode(B, Bstart, Bend);
    std::cout << "解码范围："; MyprintDecode(Bstart); std::cout << " ~ "; MyprintDecode(Bend); std::cout << std::endl;

    // 场景 C：存在其他层级值不一致，需“虚拟点”式拆分（2024-01-01 03:06 ~ 2025-02-03 10:10）
    UTSCTime* c1 = new UTSCTime(5);
    c1->system = UTSCTimeSystemType::UTC;
    c1->segmentTime[0] = { UTSCElementType::Year,  2024 };
    c1->segmentTime[1] = { UTSCElementType::Month, 1    };
    c1->segmentTime[2] = { UTSCElementType::Day,   1    };
    c1->segmentTime[3] = { UTSCElementType::Hour,  3    };
    c1->segmentTime[4] = { UTSCElementType::Minute,  6 };

    UTSCTime* c2 = new UTSCTime(5);
    c2->system = UTSCTimeSystemType::UTC;
    c2->segmentTime[0] = { UTSCElementType::Year,  2025 };
    c2->segmentTime[1] = { UTSCElementType::Month, 2    };
    c2->segmentTime[2] = { UTSCElementType::Day,   3    };
    c2->segmentTime[3] = { UTSCElementType::Hour,  10    };
    c2->segmentTime[4] = { UTSCElementType::Minute,  10};

    // 编码
    std::vector<UTSCElementCode> C;
    p->encode(c1, c2, C);
    std::cout << "[C] 2025-01-01 03:06 ~ 2025-02-03 10:10 编码：" << std::endl;
    // 编码结果是一个编码数组，对于数组中的每一个编码逐个输出
    for (auto &c: C) {
        UTSCElementCode* enc = &c;
        MyprintEncode(enc);
        std::cout << std::endl;
    }
    // 解码
    UTSCTime* Cstart=nullptr; UTSCTime* Cend=nullptr;
    p->decode(C, Cstart, Cend);
    std::cout << "解码范围："; MyprintDecode(Cstart); std::cout << " ~ "; MyprintDecode(Cend); std::cout << std::endl;

    DestroyKernelObj(p);
    delete a1; delete a2;
    delete b1; delete b2;
    delete c1; delete c2;
    delete Astart; delete Aend;
    delete Bstart; delete Bend;
    delete Cstart; delete Cend;
}

/// <summary>
/// 初始化UTC基准时间
/// </summary>
/// <returns></returns>
UTSCTime* InitUTC()
{
    //手动初始化UTC类型的时间，2024年2月10日3时2分
    UTSCTime* orgTime = new UTSCTime(5);
    orgTime->system = UTSCTimeSystemType::UTC;
    orgTime->segmentTime[0].elementType = UTSCElementType::Year;
    orgTime->segmentTime[1].elementType = UTSCElementType::Month;
    orgTime->segmentTime[2].elementType = UTSCElementType::Day;
    orgTime->segmentTime[3].elementType = UTSCElementType::Hour;
    orgTime->segmentTime[4].elementType = UTSCElementType::Minute;
    orgTime->segmentTime[0].data = 2024;
    orgTime->segmentTime[1].data = 2;
    orgTime->segmentTime[2].data = 10;
    orgTime->segmentTime[3].data = 3;
    orgTime->segmentTime[4].data = 2;

    return orgTime;
}

/// <summary>
/// 初始化UTC时间范围示例：2025年1月1日 到 2025年4月30日
/// </summary>
void InitUTCRange(UTSCTime*& start, UTSCTime*& end)
{
    start = new UTSCTime(2);  // 年-月
    end = new UTSCTime(2);

    start->system = end->system = UTSCTimeSystemType::UTC;

    start->segmentTime[0].elementType = end->segmentTime[0].elementType = UTSCElementType::Year;
    start->segmentTime[0].data = 2024;
    end->segmentTime[0].data = 2025;

    start->segmentTime[1].elementType = end->segmentTime[1].elementType = UTSCElementType::Month;
    start->segmentTime[1].data = 1;
    end->segmentTime[1].data = 4;
}


/// <summary>
/// 初始化地质基准时间
/// </summary>
/// <returns></returns>
UTSCTime* InitGeo()
{
    //手动初始化地质类型的时间，300.123Ma
    UTSCTime* orgTimeGeo = new UTSCTime(2);
    orgTimeGeo->system = UTSCTimeSystemType::Geo;
    orgTimeGeo->segmentTime[0].elementType = UTSCElementType::MegaYear;
    orgTimeGeo->segmentTime[1].elementType = NNU::UTSC::Base::UTSCElementType::KiloYear;
    orgTimeGeo->segmentTime[0].data = 300;
    orgTimeGeo->segmentTime[1].data = 123;

    return orgTimeGeo;
}

/// <summary>
/// 时间编码
/// </summary>
/// <param name="time">输入时间明文</param>
/// <param name="code">返回时间编码</param>
void encode(UTSCTime* time, UTSCElementCode*& code)
{
    //初始化结构体
    IUTSCKernel* pKernel = CreateKernelObj();

    //调用方法进行编码
    pKernel->encode(time, code);

    //释放结构体
    DestroyKernelObj(pKernel);
}


/// <summary>
/// 时间解码
/// </summary>
/// <param name="code">输入时间编码</param>
/// <param name="time">返回时间明文</param>
void decode(UTSCElementCode* code, UTSCTime*& time)
{
    //初始化结构体
    IUTSCKernel* pKernel = CreateKernelObj();

    //调用方法进行解码
    pKernel->decode(code, time);

    //释放结构体
    DestroyKernelObj(pKernel);
}

/// <summary>
/// 时间结构查询
/// </summary>
/// <param name="type">查询类型（父、子、相邻）</param>
/// <param name="code">当前时间编码</param>
/// <param name="result">查询时间编码</param>
/// <param name="size">标记输入的是时间点还是时间段</param>
void utscStructQuery(UTSCStructType type, UTSCElementCode* code, UTSCElementCode* &result, int &size)
{
    //初始化结构体
    IUTSCKernel* pKernel = CreateKernelObj();

    //调用方法进行查询
    pKernel->structQuery(type, code, result, size);

    UTSCTime* decodeResult1 = new UTSCTime(10);
    UTSCTime* decodeResult2 = new UTSCTime(10);
    UTSCTime* decodeResult3 = new UTSCTime(10);

    //调用方法进行解码，以方便查看查询结果
    pKernel->decode(code, decodeResult1);
    if (size == 2)
    {
        pKernel->decode(&result[0], decodeResult2);
        pKernel->decode(&result[1], decodeResult3);
        MyprintDecode(decodeResult2);
        std::cout << std::endl;
        MyprintDecode(decodeResult3);
        std::cout << std::endl;
        std::cout << std::endl;
    }
    else
    {
        pKernel->decode(&result[0], decodeResult2);
        MyprintDecode(decodeResult2);
        std::cout << std::endl;
        std::cout << std::endl;
    }

    //释放结构体
    DestroyKernelObj(pKernel);
}

/// <summary>
/// 时间拓扑关系查询
/// </summary>
/// <param name="code1">时间编码1</param>
/// <param name="code2">时间编码2</param>
/// <param name="type">标记输入的是时间点还是时间段</param>
/// <returns>拓扑关系</returns>
UTSCTopoType topoQuery(UTSCElementCode* code1, UTSCElementCode* code2,int type)
{
    //初始化结构体
    IUTSCKernel* pKernel = CreateKernelObj();

    //调用方法进行查询
    UTSCTopoType result = pKernel->topoQuery(code1, code2, type);

    //释放结构体
    DestroyKernelObj(pKernel);

    return result;
}

/// <summary>
/// 打印编码结果
/// </summary>
/// <param name="encodetime"></param>
void MyprintEncode(UTSCElementCode*& encodetime)
{
    int i = 0;
    while (encodetime->segmentCode[i].params != 0b00000000 && i < encodetime->size)
    {
        if (i == 0)
            printLastNBits(encodetime->signal, 1);
        int number = (encodetime->segmentCode[i].params) & 0x0F;
        printBinary(encodetime->segmentCode[i].params);
        printLastNBits(encodetime->segmentCode[i].codes, number);
        i++;
    }
}

/// <summary>
/// 打印解码结果
/// </summary>
/// <param name="decodetime"></param>
void MyprintDecode(UTSCTime*& decodetime)
{
    int i = 0;
    while (decodetime->segmentTime[i].elementType != UTSCElementType::Unknown && i < decodetime->size)
    {
        switch (decodetime->segmentTime[i].elementType)
        {
        case UTSCElementType::GigaYear:
            std::cout << decodetime->segmentTime[i].data << "十亿年";
            break;
        case UTSCElementType::MegaYear:
            std::cout << decodetime->segmentTime[i].data << "百万年";
            break;
        case UTSCElementType::KiloYear:
            std::cout << decodetime->segmentTime[i].data << "千年";
            break;
        case UTSCElementType::Year:
            std::cout << decodetime->segmentTime[i].data << "年";
            break;
        case UTSCElementType::Month:
            std::cout << decodetime->segmentTime[i].data << "月";
            break;
        case UTSCElementType::Day:
            std::cout << decodetime->segmentTime[i].data << "日";
            break;
        case UTSCElementType::Hour:
            std::cout << decodetime->segmentTime[i].data << "时";
            break;
        case UTSCElementType::Minute:
            std::cout << decodetime->segmentTime[i].data << "分";
            break;
        case UTSCElementType::Second:
            std::cout << decodetime->segmentTime[i].data << "秒";
            break;
        case UTSCElementType::Millisecond:
            std::cout << decodetime->segmentTime[i].data << "毫秒";
            break;
        }
        i++;
    }
}

/// <summary>
/// 将二进制打印为明文
/// </summary>
/// <param name="n"></param>
void printBinary(uint8_t n) {
    for (int i = 7; i >= 0; --i) {
        std::cout << ((n >> i) & 1);
    }
}

void printLastNBits(uint16_t num, int n) {
    // 计算要打印的掩码
    unsigned short mask = (1 << n) - 1;    
    unsigned short lastNBits = num & mask; 

    // 打印最后 n 位
    for (int i = n - 1; i >= 0; --i) {
        std::cout << ((lastNBits >> i) & 1);
    }
}

/// <summary>
/// 打印拓扑查询结果
/// </summary>
/// <param name="type"></param>
void printTopoQueryResult(int type)
{
    char* topoTypeStrings[] = { "Before", "After", "StartWith", "StartBy", "FinishWith", "FinishBy", "Equal", "OverlapWith", "OverlapBy", "Contain", "ContainedBy", "MetBy", "MeetWith" };
    std::cout << topoTypeStrings[type] << std::endl;
}